
//muduo/examples/asio/chat/client.cc

#include "codec.h"

#include <muduo/base/Logging.h>
#include <muduo/base/Mutex.h>
#include <muduo/net/EventLoopThread.h>
#include <muduo/net/TcpClient.h>


#include <boost/filesystem.hpp>

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>

#include "CameraProto.pb.h"

#define LOG std::cout << __FILE__ <<" "<< __LINE__<< " " << __FUNCTION__ << " "

static void write(std::string name, std::string &msg) {
    std::ofstream ofile;
    ofile.open(name, std::ios::binary);
    ofile << msg;
    ofile.close();
}


static void ReadCamRetResponseList(std::string fullMsg) {

    LOG << " FullMsg size read From FileSys:" << fullMsg.size() << std::endl;
    ProtoResponse response_b;
    response_b.ParseFromString(fullMsg);
    std::string bodyMsg = response_b.protobody();
    LOG << "Camera Response TYPE: " << response_b.prototype() << std::endl;
    if (response_b.prototype() == PUSH_COMPARE_RESULT) {
        LOG << response_b.result() << std::endl;
        LOG << response_b.bodylength() << std::endl;

        CompareResponseList cameraResultResponseList_b;
        cameraResultResponseList_b.ParseFromString(bodyMsg);
        LOG << "CompareResponseList cnt:" << cameraResultResponseList_b.responsecount() << std::endl;
        int cameraResultResponse = cameraResultResponseList_b.responselist_size();
        for (int i = 0; i < cameraResultResponse; i++) {
            CompareResponse camResp = cameraResultResponseList_b.responselist(i);
            LOG << " camResp: " << camResp.ip() << std::endl;
            LOG << " camResp: " << camResp.port() << std::endl;
            LOG << " camResp: " << camResp.channel() << std::endl;

            struct timeval t;
            gettimeofday(&t, NULL);
            std::string pic = camResp.regimg();
            std::string pic2 = camResp.capimg();

            const std::string outDir = "targetOut";
            if (!boost::filesystem::exists(outDir)) {
                boost::filesystem::create_directories(outDir);
            }
            if (boost::filesystem::exists(outDir)) {
                write(outDir + "/" + std::to_string(t.tv_sec) + "." + std::to_string(t.tv_usec) + "_s:" +
                      std::to_string(camResp.score()) + "_buf1.jpg", pic);
                write(outDir + "/" + std::to_string(t.tv_sec) + "." + std::to_string(t.tv_usec) + "_s:" +
                      std::to_string(camResp.score()) + "_buf2.jpg", pic2);
            }
        }
    } else if (response_b.prototype() == QUERY_COMPARE_RESULT) {
        LOG << "QUERY_COMPARE_RESULT" << response_b.result() << std::endl;
        LOG << "QUERY_COMPARE_RESULT:" << response_b.resultmsg() << std::endl;
    }

}

static std::string read(std::string name) {
    std::string msg;

    std::ifstream t;
    int length;
    t.open(name, std::ios::binary);      // open input file
    t.seekg(0, std::ios::end);    // go to the end
    length = t.tellg();           // report location (this is the length)
    t.seekg(0, std::ios::beg);    // go back to the beginning
    char buffer[length];    // allocate memory for a buffer of appropriate dimension
    t.read(buffer, length);       // read the whole file into the buffer
    t.close();

    msg.assign(buffer, length);

    return msg;
}


class ChatClient : boost::noncopyable {
public:
//首先在构造函数里注册回调，并使用跟前面一样的LengthHeaderCodec作为中间层，负责打包、分包。
    ChatClient(muduo::net::EventLoop *loop, const muduo::net::InetAddress &serverAddr)
            : client_(loop, serverAddr, "ChatClient"),
              codec_(boost::bind(&ChatClient::onStringMessage, this, _1, _2,
                                 _3)) //向codec_注册ChatClient::onStringMessage()
    {
        client_.setConnectionCallback(
                boost::bind(&ChatClient::onConnection, this, _1));
        client_.setMessageCallback(
                boost::bind(&LengthHeaderCodec::onMessage, &codec_, _1, _2, _3));
        client_.enableRetry();
    }

    void connect() {
        client_.connect();
    }

    void disconnect() {
        client_.disconnect();
    }

//write()会由main线程调用
    void write(const muduo::StringPiece &message) {
        muduo::MutexLockGuard lock(mutex_);    //加锁保护shared_ptr
        if (connection_) {
            codec_.send(get_pointer(connection_), message);
        }
    }


//onConnection()由EventLoop线程调用
    void onConnection(const muduo::net::TcpConnectionPtr &conn) {
        LOG_INFO << conn->localAddress().toIpPort() << " -> "
                 << conn->peerAddress().toIpPort() << " is "
                 << (conn->connected() ? "UP" : "DOWN");

        muduo::MutexLockGuard lock(mutex_);    //加锁保护shared_ptr
        if (conn->connected()) {
            connection_ = conn;
        } else {
            connection_.reset();
        }
    }

//.......由EventLoop线程调用,把消息打印到屏幕
    void onStringMessage(const muduo::net::TcpConnectionPtr &,
                         const std::string &message,
                         muduo::Timestamp) {
        printf("<<<<<<<<<<<<<<<<< %s\n", message.c_str());
        std::cout << "**************************************" << std::endl;
        ReadCamRetResponseList(message);
    }

//数据成员
public:
    muduo::net::TcpClient client_;
    LengthHeaderCodec codec_;
    muduo::MutexLock mutex_;
    muduo::net::TcpConnectionPtr connection_
    GUARDED_BY(mutex_);
};

int main(int argc, char *argv[]) {
    LOG_INFO << "pid = " << getpid();
    if (argc > 2) {
        muduo::net::EventLoopThread loopThread;
        uint16_t port = static_cast<uint16_t>(atoi(argv[2]));
        muduo::net::InetAddress serverAddr(argv[1], port);    //初始化sockaddr_in

        ChatClient client(loopThread.startLoop(), serverAddr);    //初始化聊天客户端
        client.connect();                    //发起连接
        std::string line;
        while (std::getline(std::cin, line))    //读取键盘输入
        {
//            client.write(line);    //发送数据行
            const std::string protoFile = "cameraReqRetReq_180.protobin";
            if (!boost::filesystem::exists(protoFile)) {
                std::cout << protoFile << " not exist" << std::endl;
                exit(-1);
            }
            std::string msg = read(protoFile);
            std::cout << "SENDING msg:" << msg << std::endl;
//            client.connection_->send(msg);
            client.write(msg);

        }
        client.disconnect();    //断开连接
        muduo::CurrentThread::sleepUsec(1000 * 1000);  // wait for disconnect, see ace/logging/client.cc
    } else {
        printf("Usage: %s host_ip port\n", argv[0]);
    }
}
